/**
 *  @file
 *  @brief   三维空间矢量
 *  @author  wanghuan
 *  @date    2024.02.29
 *  @version  v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#ifndef Algebra_Vector3D_h
#define Algebra_Vector3D_h

// #pragma once
// #include "DataStructure/Common/include/DataStructureExport.h"
// #include "DataStructure/Common/include/DataStructureNamespace.h"
// #include "DataStructure/Common/include/Out.h"
// #include "DataStructure/Common/include/Real.h"
#include "Matrix.h"

SG_NAMESPACE_OPEN
namespace Algebra
{
    using Real_t = ::SG::Algebra::Real_t;
    using Matrixd = ::SG::Algebra::Matrixd;

    /** @brief 三维空间矢量
     *
     * 使用三个分量来描述方向
     */
    struct ALGEBRA_EXPORT Vector3D
    {
        Vector3D (Real_t x, Real_t y, Real_t z)
            : m_x (x), m_y (y), m_z (z) {};
        Vector3D () : m_x (0), m_y (0), m_z (0) {};

      public:
        /** @brief  将向量本身变成单位向量，并通过引用返回其模长
         *
         *  避免对零向量使用本函数
         */
        Vector3D& Normalize (Real_t& norm);

        Vector3D& Normalize ();

        /** @brief 矢量的坐标变换
         *  @param [in] T 坐标变换矩阵
         */
        Vector3D Rotate (const Matrixd& T) const;

        Real_t operator() (const int i) const;

        /** 重载*=， 空间向量本身乘以常数 */
        Vector3D& operator*= (Real_t factor);

        /** 重载*， 空间向量乘以常数 */
        Vector3D operator* (Real_t factor) const;

        /** @brief 重载向量+=
         *  @author Yuan Chenxi 2024,05.10添加
         */
        Vector3D& operator+= (const Vector3D& b);

        /** @brief 重载向量+
         *  @author Yuan Chenxi 2024,05.10添加
         */
        Vector3D operator+ (const Vector3D& b) const;

        /** @brief 重载向量-=
         *  @author Yuan Chenxi 2024,05.10添加
         */
        Vector3D& operator-= (const Vector3D& b);

        /** @brief 重载向量-
         *  @author Yuan Chenxi 2024,05.10添加
         */
        Vector3D operator- (const Vector3D& b) const;

        /** @brief 是否为零向量*/
        bool IsZero () const;
        
        /// @brief 是否是单位向量
        bool IsUnit () const;

      public:
        Real_t m_x = 0.0;  ///< x component
        Real_t m_y = 0.0;  ///< y component
        Real_t m_z = 0.0;  ///< z component
    };

    /** @brief 计算两个向量的叉乘
     * 使用右手法则
     */
    ALGEBRA_EXPORT Vector3D Cross (const Vector3D& a, const Vector3D& b);

    /** @brief 计算两个向量的内积
     * Yuan Chenxi 2024,05.10添加
     */
    ALGEBRA_EXPORT Real_t dot (const Vector3D& a, const Vector3D& b);

    /// @brief 两个向量是否相等，辅助测试
    ALGEBRA_EXPORT bool operator== (const Vector3D& a, const Vector3D& b);
};  // namespace Algebra

SG_NAMESPACE_CLOSE

#endif  // Algebra_Vector3D_h